home *** CD-ROM | disk | FTP | other *** search
- /* $VER: pasm output_elf.c V0.5 (12.10.97)
- *
- * This file is part of pasm, a portable PowerPC assembler.
- * Copyright (c) 1997 Frank Wille
- *
- * pasm is freeware and part of the portable and retargetable ANSI C
- * compiler vbcc, copyright (c) 1995-97 by Volker Barthelmann.
- * pasm may be freely redistributed as long as no modifications are
- * made and nothing is charged for it. Non-commercial usage is allowed
- * without any restrictions.
- * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
- * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
- *
- *
- * v0.5 (12.10.97) phx
- * Removed "pasm V0.x" from .comment section.
- * v0.3 (10.04.97) phx
- * Fixed enforcer-hit, when external references are present.
- * Some vbcc-specific changes.
- * Support for little endian architectures.
- * v0.2 (25.03.97) phx
- * Writes ELF object for 32-bit PowerPC big-endian. Either absolute
- * or ELF output format may be selected. ELF is default for all
- * currently supported platforms. PPCasm supports nine different
- * relocation types (there are much more...).
- * Compiles and works also under NetBSD/amiga (68k).
- * Changed function declaration to 'new style' in all sources
- * (to avoid problems with '...' for example).
- * File created.
- */
-
-
- #define OUTPUT_ELF_C
- #include "ppcasm.h"
- #include "elf.h"
- #include <time.h>
-
-
- struct StrTabList {
- struct list l;
- uint32 index;
- };
-
- struct StrTabNode {
- struct node n;
- char *str;
- };
-
- struct ShdrNode {
- struct node n;
- struct Elf32_Shdr s;
- };
-
- struct SymbolNode {
- struct node n;
- char *name;
- struct Elf32_Sym s;
- };
-
- struct RelaNode {
- struct node n;
- struct Elf32_Rela r;
- };
-
-
- static struct Elf32_Ehdr elf_header = {
- { 0x7f,'E','L','F',ELFCLASS32,0,EV_CURRENT,0,0,0,0,0,0,0,0,0 },
- ECH(ET_REL),ECH(EM_POWERPC),ECW(EV_CURRENT),0,0,0,0,
- ECH(sizeof(struct Elf32_Ehdr)),
- 0,0,ECH(sizeof(struct Elf32_Shdr)),0,0
- };
- static char *output_name;
-
-
- void output_elf32msb(struct GlobalVars *);
-
- static struct ShdrNode *addShdr(struct list *);
- static struct SymbolNode *addSymbol(struct list *,struct StrTabList *,char *);
- static uint32 addString(struct StrTabList *,char *);
- static void addRela(struct list *,uint32,uint32,uint32);
- static void fw(FILE *,void *,size_t);
-
-
-
- void output_elf32msb(struct GlobalVars *gv)
- {
- struct list shdrlist,symlist,relalist;
- struct StrTabList shstrlist,strlist;
- struct ShdrNode *shn;
- struct SymbolNode *sym;
- uint32 symtabidx,strtabidx,shstrtabidx,firstglobal,align1,align2;
- uint32 roffset=0,soffset=sizeof(struct Elf32_Ehdr);
- uint32 shdrindex=0,symindex=0;
- struct Section *nextsec,*sec=(struct Section *)gv->sectionlist.first;
- struct Symbol *symchain;
- int i;
- FILE *fp;
-
- /* init */
- output_name = gv->dest_name;
- elf_header.e_ident[EI_DATA] = ELFDATA2MSB;
- initlist(&shdrlist);
- initlist(&symlist);
- initlist(&relalist);
- shstrlist.index = strlist.index = 0;
- initlist(&shstrlist.l);
- initlist(&strlist.l);
- addString(&shstrlist,""); /* first string is always "" */
- symtabidx = addString(&shstrlist,".symtab");
- strtabidx = addString(&shstrlist,".strtab");
- shstrtabidx = addString(&shstrlist,".shstrtab");
- addShdr(&shdrlist); /* first Shdr is always zero */
- addString(&strlist,"");
- addSymbol(&symlist,NULL,NULL); /* first symbol table entry always empty */
-
- /* source file name symbol */
- if (gv->file) {
- ++symindex;
- sym = addSymbol(&symlist,&strlist,gv->file);
- sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,STT_FILE);
- sym->s.st_shndx = ECH(SHN_ABS);
- }
-
- /* generate section headers for program sections */
- while (nextsec = (struct Section *)sec->n.next) {
- if (!(sec->flags & SF_DISCARD) && sec->size > 0) {
- sec->index = ++shdrindex;
- shn = addShdr(&shdrlist);
- shn->s.sh_name = ECVW(addString(&shstrlist,sec->name));
- if (sec->type==ST_UDATA || (sec->flags&SF_UNINITIALIZED))
- shn->s.sh_type = ECW(SHT_NOBITS);
- else
- shn->s.sh_type = ECW(SHT_PROGBITS);
- shn->s.sh_flags = ECW(SHF_ALLOC);
- if (sec->protection & SP_WRITE)
- shn->s.sh_flags |= ECW(SHF_WRITE);
- if (sec->protection & SP_EXEC)
- shn->s.sh_flags |= ECW(SHF_EXECINSTR);
- shn->s.sh_offset = ECVW(soffset);
- shn->s.sh_size = ECVW(sec->size);
- if (shn->s.sh_type == ECW(SHT_PROGBITS))
- soffset += sec->size;
- shn->s.sh_addralign = ECVW(1<<(uint32)sec->alignment);
- /* add section symbol */
- sym = addSymbol(&symlist,NULL,NULL);
- sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,STT_SECTION);
- sym->s.st_shndx = ECVH((uint16)shdrindex);
- ++symindex;
- }
- sec = nextsec;
- }
-
- /* comment section */
- if (gv->ident || gv->vc) {
- ++shdrindex;
- shn = addShdr(&shdrlist);
- shn->s.sh_name = ECVW(addString(&shstrlist,".comment"));
- shn->s.sh_type = ECW(SHT_PROGBITS);
- shn->s.sh_offset = ECVW(soffset);
- shn->s.sh_size = 1; /* zero-byte */
- if (gv->ident)
- shn->s.sh_size += (uint32)strlen(gv->ident)+1;
- if (gv->vc)
- shn->s.sh_size += 12;
- soffset += shn->s.sh_size;
- #ifdef LITTLEENDIAN
- shn->s.sh_size = l2bw(shn->s.sh_size);
- #endif
- shn->s.sh_addralign = ECW(1);
- /* add section symbol */
- sym = addSymbol(&symlist,NULL,NULL);
- sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,STT_SECTION);
- sym->s.st_shndx = ECVH((uint16)shdrindex);
- ++symindex;
- }
-
- /* build symbol table */
- for (i=0; i<SYMHTABSIZE; i++) { /* first, symbols with local binding */
- symchain = gv->symbols[i];
- while (symchain) {
- if (*(symchain->name) != '.') { /* '.symbols' are ignored */
- if (symchain->type==SYM_ABS || symchain->type==SYM_RELOC) {
- if (symchain->bind == SYMB_LOCAL) {
- ++symindex;
- sym = addSymbol(&symlist,&strlist,symchain->name);
- sym->s.st_value = ECVW(symchain->value);
- sym->s.st_size = ECVW(symchain->size);
- sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,symchain->type);
- if (symchain->type == SYM_ABS)
- sym->s.st_shndx = ECH(SHN_ABS);
- else
- sym->s.st_shndx = ECVH((uint16)symchain->relsect->index);
- }
- }
- }
- symchain = symchain->hash_chain;
- }
- }
- firstglobal = symindex + 1;
- for (i=0; i<SYMHTABSIZE; i++) { /* then, global and weak symbols */
- symchain = gv->symbols[i];
- while (symchain) {
- if (*(symchain->name) != '.') { /* '.symbols' are ignored */
- if (symchain->type==SYM_ABS || symchain->type==SYM_RELOC) {
- if (symchain->bind > SYMB_LOCAL) {
- ++symindex;
- sym = addSymbol(&symlist,&strlist,symchain->name);
- sym->s.st_value = ECVW(symchain->value);
- sym->s.st_size = ECVW(symchain->size);
- sym->s.st_info = ELF32_ST_INFO(symchain->bind,symchain->type);
- if (symchain->type == SYM_ABS)
- sym->s.st_shndx = ECH(SHN_ABS);
- else
- sym->s.st_shndx = ECVH((uint16)symchain->relsect->index);
- }
- }
- }
- symchain = symchain->hash_chain;
- }
- }
-
- /* ".rela.xxx" relocation sections */
- sec = (struct Section *)gv->sectionlist.first;
- while (nextsec = (struct Section *)sec->n.next) {
- if (!(sec->flags & SF_DISCARD) && sec->size > 0) {
- struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
- struct XReference *nextxref;
- struct XReference *xref=(struct XReference *)sec->xreflist.first;
- uint32 ro=roffset;
- char *sptr;
-
- while (nextrel = (struct Reloc *)rel->n.next) {
- addRela(&relalist,rel->offset,rel->addend,
- ELF32_R_INFO(rel->relocsect->index,rel->type));
- roffset += sizeof(struct Elf32_Rela);
- rel = nextrel;
- }
-
- while (nextxref = (struct XReference *)xref->n.next) {
- struct SymbolNode *nextsym;
- char *xname = xref->xsymbol->name;
- uint32 sidx=0;
-
- /* check if referenced symbol is already in symbol table */
- sym = (struct SymbolNode *)symlist.first;
- while (nextsym = (struct SymbolNode *)sym->n.next) {
- if (sym->name)
- if (!strcmp(xname,sym->name))
- break;
- ++sidx;
- sym = nextsym;
- }
- if (nextsym==NULL) {
- sidx = ++symindex;
- sym = addSymbol(&symlist,&strlist,xname);
- sym->s.st_info = ELF32_ST_INFO(STB_GLOBAL,STT_NOTYPE);
- }
- addRela(&relalist,xref->offset,xref->addend,
- ELF32_R_INFO(sidx,xref->type));
- roffset += sizeof(struct Elf32_Rela);
- xref = nextxref;
- }
-
- if (ro != roffset) { /* were there any relocations? */
- sptr = (char *)alloc(strlen(sec->name) + 5);
- sprintf(sptr,".rela%s",sec->name);
- ++shdrindex;
- shn = addShdr(&shdrlist);
- shn->s.sh_name = ECVW(addString(&shstrlist,sptr));
- shn->s.sh_type = ECW(SHT_RELA);
- shn->s.sh_offset = ro; /* relative offset, corrected later */
- shn->s.sh_size = ECVW(roffset - ro);
- /* sh_link will be set later, when .symtab exists */
- shn->s.sh_info = ECVW(sec->index); /* shdr idx to which reloc applies */
- shn->s.sh_addralign = ECW(4);
- shn->s.sh_entsize = ECW(sizeof(struct Elf32_Rela));
- }
- }
- sec = nextsec;
- }
-
- /* ".shstrtab" section header string table */
- ++shdrindex;
- shn = addShdr(&shdrlist);
- shn->s.sh_name = ECVW(shstrtabidx);
- shn->s.sh_type = ECW(SHT_STRTAB);
- shn->s.sh_offset = ECVW(soffset);
- shn->s.sh_size = ECVW(shstrlist.index);
- shn->s.sh_addralign = ECW(1);
- soffset += shstrlist.index;
- align1 = ((soffset + 3) & ~3) - soffset;
- soffset += align1;
-
- elf_header.e_shoff = ECVW(soffset);
- soffset += (shdrindex+3)*sizeof(struct Elf32_Shdr);
- elf_header.e_shstrndx = ECVH((uint16)shdrindex);
- elf_header.e_shnum = ECVH((uint16)shdrindex+3);
-
- /* ".symtab" symbol table */
- ++shdrindex;
- ++symindex; /* number of symbol in symbol table */
- shn = addShdr(&shdrlist);
- shn->s.sh_name = ECVW(symtabidx);
- shn->s.sh_type = ECW(SHT_SYMTAB);
- shn->s.sh_offset = ECVW(soffset);
- shn->s.sh_size = symindex*sizeof(struct Elf32_Sym);
- shn->s.sh_link = ECVW(shdrindex+1); /* associated .strtab section */
- shn->s.sh_info = ECVW(firstglobal); /* first non-local symbol index */
- shn->s.sh_addralign = ECW(4);
- shn->s.sh_entsize = ECW(sizeof(struct Elf32_Sym));
- soffset += shn->s.sh_size;
- #ifdef LITTLEENDIAN
- shn->s.sh_size = l2bw(shn->s.sh_size);
- #endif
-
- /* ".strtab" string table */
- shn = addShdr(&shdrlist);
- shn->s.sh_name = ECVW(strtabidx);
- shn->s.sh_type = ECW(SHT_STRTAB);
- shn->s.sh_offset = ECVW(soffset);
- shn->s.sh_size = ECVW(strlist.index);
- shn->s.sh_addralign = ECW(1);
- soffset += strlist.index;
- align2 = ((soffset + 3) & ~3) - soffset;
- soffset += align2; /* offset for first Rela-entry */
-
- /* create output file */
- if (fp = fopen(output_name,"w")) {
- struct StrTabNode *stn;
- struct RelaNode *rn;
-
- fw(fp,&elf_header,sizeof(struct Elf32_Ehdr)); /* write header */
-
- /* write initialized section contents */
- sec = (struct Section *)gv->sectionlist.first;
- while (nextsec = (struct Section *)sec->n.next) {
- if (!(sec->flags & (SF_DISCARD|SF_UNINITIALIZED)))
- fw(fp,sec->contents,sec->size);
- sec = nextsec;
- }
-
- /* write comment section */
- if (gv->ident || gv->vc) {
- fw(fp,gv->alignment_bytes,1); /* write leading 0-byte */
- if (gv->ident)
- fw(fp,gv->ident,strlen(gv->ident)+1);
- if (gv->vc) {
- uint32 v = ECW(0x16020303);
-
- fw(fp,&v,4);
- v = ECVW((uint32)time(NULL));
- fw(fp,&v,4);
- v = ECW(0x03030216);
- fw(fp,&v,4);
- }
- }
-
- /* write .shstrtab string table */
- while (stn = (struct StrTabNode *)remhead(&shstrlist.l))
- fw(fp,stn->str,strlen(stn->str)+1);
-
- /* write section headers */
- fw(fp,gv->alignment_bytes,align1);
- while (shn = (struct ShdrNode *)remhead(&shdrlist)) {
- if (shn->s.sh_type == SHT_RELA) {
- shn->s.sh_offset += soffset; /* set correct offset */
- #ifdef LITTLEENDIAN
- shn->s.sh_offset = l2bw(shn->s.sh_offset);
- #endif
- shn->s.sh_link = ECVW(shdrindex); /* index of associated symbol table */
- }
- fw(fp,&(shn->s),sizeof(struct Elf32_Shdr));
- }
-
- /* write symbol table */
- while (sym = (struct SymbolNode *)remhead(&symlist))
- fw(fp,&(sym->s),sizeof(struct Elf32_Sym));
-
- /* write .strtab string table */
- while (stn = (struct StrTabNode *)remhead(&strlist.l))
- fw(fp,stn->str,strlen(stn->str)+1);
-
- /* write relocations */
- fw(fp,gv->alignment_bytes,align2);
- while (rn = (struct RelaNode *)remhead(&relalist))
- fw(fp,&(rn->r),sizeof(struct Elf32_Rela));
-
- fclose(fp);
- }
- else
- error(25,output_name); /* unable to create output file */
- }
-
-
- static struct ShdrNode *addShdr(struct list *l)
- {
- struct ShdrNode *s = alloczero(sizeof(struct ShdrNode));
-
- addtail(l,&(s->n));
- return (s);
- }
-
-
- static struct SymbolNode *addSymbol(struct list *l,struct StrTabList *sl,
- char *name)
- {
- struct SymbolNode *sn = alloczero(sizeof(struct SymbolNode));
-
- addtail(l,&(sn->n));
- if (name) {
- sn->name = name;
- sn->s.st_name = ECVW(addString(sl,name));
- }
- return (sn);
- }
-
-
- static uint32 addString(struct StrTabList *sl,char *s)
- {
- struct StrTabNode *sn = alloc(sizeof(struct StrTabNode));
- uint32 idx = sl->index;
-
- sn->str = s;
- addtail(&(sl->l),&(sn->n));
- sl->index += (uint32)strlen(s) + 1;
- return (idx);
- }
-
-
- static void addRela(struct list *l,uint32 o,uint32 a,uint32 i)
- {
- struct RelaNode *rn = alloc(sizeof(struct RelaNode));
-
- rn->r.r_offset = ECVW(o);
- rn->r.r_addend = ECVW(a);
- rn->r.r_info = ECVW(i);
- addtail(l,&(rn->n));
- }
-
-
- static void fw(FILE *fp,void *buf,size_t len)
- {
- if (len) {
- if (!fwrite(buf,1,len,fp)) {
- fclose(fp);
- error(26,output_name); /* write error */
- }
- }
- }
-